package com.example.module_course.common

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.calculateEndPadding
import androidx.compose.foundation.layout.calculateStartPadding
import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.staggeredgrid.StaggeredGridCells
import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.unit.dp


internal class FixedAndAdaptive(private val minCount: Int, private val maxSize: Dp) : GridCells {
    init {
        require(minCount > 0)
    }

    override fun Density.calculateCrossAxisCellSizes(availableSize: Int, spacing: Int): List<Int> {
        val count = maxOf((availableSize + spacing) / (maxSize.roundToPx() + spacing), 1)
        return calculateCellsCrossAxisSizeImpl(availableSize, if (count < minCount) minCount else count, spacing)
    }

    override fun hashCode(): Int {
        return -minCount and maxSize.hashCode()
    }

    override fun equals(other: Any?): Boolean {
        return other is FixedAndAdaptive && minCount == other.minCount && maxSize == other.maxSize
    }

    fun getRowCount(
        density: Density,
        maxWidth: Int,
        contentPadding: PaddingValues = PaddingValues(0.dp),
        horizontalArrangement: Arrangement.Horizontal = Arrangement.Start,
    ): Int {
        with(density) {
            val horizontalPadding = contentPadding.calculateStartPadding(LayoutDirection.Ltr) + contentPadding.calculateEndPadding(LayoutDirection.Ltr)
            val gridWidth = maxWidth - horizontalPadding.roundToPx()
            return calculateCrossAxisCellSizes(gridWidth, horizontalArrangement.spacing.roundToPx()).size
        }
    }

    private fun calculateCellsCrossAxisSizeImpl(gridSize: Int, slotCount: Int, spacing: Int): List<Int> {
        val gridSizeWithoutSpacing = gridSize - spacing * (slotCount - 1)
        val slotSize = gridSizeWithoutSpacing / slotCount
        val remainingPixels = gridSizeWithoutSpacing % slotCount
        return List(slotCount) {
            slotSize + if (it < remainingPixels) 1 else 0
        }
    }
}

internal class StaggeredFixedAndAdaptive(private val minCount: Int, private val maxSize: Dp) : StaggeredGridCells {
    init {
        require(minCount > 0)
    }

    override fun Density.calculateCrossAxisCellSizes(availableSize: Int, spacing: Int): IntArray {
        val count = maxOf((availableSize + spacing) / (maxSize.roundToPx() + spacing), 1)
        return calculateCellsCrossAxisSizeImpl(availableSize, if (count < minCount) minCount else count, spacing)
    }

    override fun hashCode(): Int {
        return -minCount and maxSize.hashCode()
    }

    override fun equals(other: Any?): Boolean {
        return other is StaggeredFixedAndAdaptive && minCount == other.minCount && maxSize == other.maxSize
    }

    private fun calculateCellsCrossAxisSizeImpl(gridSize: Int, slotCount: Int, spacing: Int): IntArray {
        val gridSizeWithoutSpacing = gridSize - spacing * (slotCount - 1)
        val slotSize = gridSizeWithoutSpacing / slotCount
        val remainingPixels = gridSizeWithoutSpacing % slotCount
        return IntArray(slotCount) {
            slotSize + if (it < remainingPixels) 1 else 0
        }
    }
}
